package com.sinosoft.sinopay.web.batch.web.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.fastjson.JSONObject;
import com.sinosoft.sinocloud.platform.base.SinoBaseController;
import com.sinosoft.sinocloud.platform.common.exception.biz.BizDataErrException;
import com.sinosoft.sinocloud.platform.common.exception.biz.SignErrException;
import com.sinosoft.sinocloud.platform.common.exception.biz.SinoBizException;
import com.sinosoft.sinocloud.platform.common.util.StringUtil;
import com.sinosoft.sinopay.web.batch.biz.service.BatchPayService;
import com.sinosoft.sinopay.web.batch.biz.service.PaymentBatchService;
import com.sinosoft.sinopay.web.batch.config.ENUM_BIZ_TRANSTYPE;
import com.sinosoft.sinopay.web.batch.dto.BatchInfo;
import com.sinosoft.sinopay.web.batch.dto.BatchResponseXML;
import com.sinosoft.sinopay.web.batch.dto.RequestBaseXml;
import com.sinosoft.sinopay.web.batch.dto.RequestEbizJson;
import com.sinosoft.sinopay.web.batch.dto.RequestHead;
import com.sinosoft.sinopay.web.batch.dto.RequestParamsDTO;
import com.sinosoft.sinopay.web.batch.dto.RequestSearchBaseXml;
import com.sinosoft.sinopay.web.batch.dto.ResponseBase;
import com.sinosoft.sinopay.web.batch.dto.ResponseBaseXml;
import com.sinosoft.sinopay.web.batch.dto.ResponseHead;
import com.sinosoft.sinopay.web.batch.dto.ResultInfo;
import com.sinosoft.sinopay.web.batch.dto.SearchHead;
import com.sinosoft.sinopay.web.batch.dto.SearchResponseBaseXml;
import com.sinosoft.sinopay.web.batch.dto.SearchResponseHead;
import com.sinosoft.sinopay.web.batch.dto.SearchResponseXML;
import com.sinosoft.sinopay.web.batch.dto.SearchResultInfo;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;


/**
 * 【 批量任务接口 】
 *
 * @author chenzhiheng
 * @version V1.0
 * @date 16/12/20
 */
@Controller
@RequestMapping("/sinopay")
public class BatchPayController extends SinoBaseController {

    private String autograph = "_SINOPAY_BATCH";

    @Autowired
    private BatchPayService batchPayService;

    @Autowired
    PaymentBatchService paymentBatchService;

    /**
     * 批量报文请求入口
     *
     * @param request
     * @param response
     * @Title: sendBatchMsg
     */
    @RequestMapping("/batchPay.do")
    public void sendBatchMsg(HttpServletRequest request, HttpServletResponse response) {
        ResponseBase responseXml = new ResponseBase();
        ResponseHead resHead = new ResponseHead();
        RequestHead  reqhead=new RequestHead();
        BatchInfo batch=new BatchInfo();
        //TODO 请求日志
        XStream xstream = new XStream(new DomDriver());
        //对指定的类使用Annotations 进行序列化
        xstream.processAnnotations(RequestBaseXml.class);
        try {
            //接收请求参数
            String toDealRequest = request.getParameter("request_xml");
            String sign = request.getParameter("sign");
            //报文解密
            logger.info("请求密文为：" + toDealRequest + "签名为：" + sign);
//            String requestXml = SecurityUtil.aesDecrypt(toDealRequest, autograph);
//            logger.info("请求报文为：" + requestXml);

            //解析报文转换为请求报文标准DTO
           // RequestEbizJson requestObj = JSONObject.parseObject(toDealRequest, RequestEbizJson.class);
            RequestBaseXml requestObj = (RequestBaseXml) xstream.fromXML(toDealRequest);
            //封装报文头为请求参数标准DTO
            //RequestBaseXml requestBaseXml= requestObj.getBatchTransReq();
            RequestParamsDTO requestParams = getRequestMustParams(requestObj.getBatchTransHead());
            //获得业务类型，并校验业务类型合法性（是否存在该业务类型）
            String bizType = requestParams.getBatchBizType();
            String bizValue = ENUM_BIZ_TRANSTYPE.getEnumValueByKey(bizType);
            if (StringUtil.isEmpty(bizValue)) {
                throw new BizDataErrException("业务类型错误，非法业务类型为" + bizType);
            }
            String sourceCode = requestParams.getMerchantCode();//商户编码
            String serialNo = requestParams.getBatchSerialNo();//业务流水号
            String payRequestTime=reqhead.getPayRequestTime();
            //String resultCode=resHead.getResultCode();
            //String resultMsg=resHead.getResultMsg();
            //报文验证签名及商户编码合法性
            //paymentBatchService.getAllMerchantSignKeys(sign, toDealRequest,sourceCode);
            //初始化返回报文头
            resHead.setSerialNo(serialNo);//业务流水号
            resHead.setMerchantCode(sourceCode);//商户编码
            resHead.setPayRequestDate(payRequestTime);//请求时间
           //resHead.setResultCode(resultCode);//返回码
           //resHead.setResultMsg(resultMsg);//错误返回码说明
            resHead.setSign(sign);//Sign	签名
            responseXml.setBatchTransHead(resHead);//生成返回报文头
            //TODO 生成记录报文日志
            //调用服务，获得报文体
            ResultInfo result = batchPayService.callBizService(requestObj);
            result.setBatchBizType(reqhead.getBatchBizType());//业务类型
            result.setTotalItem(batch.getTotalItem());//总记录数
            result.setTotalSum(String.valueOf(batch.getTotalSum()));//总交易金额
            //封装成功报文
            responseXml.success();//生成返回报文，初始化报文头
            responseXml.setResultInfo(result);//报文体
        } catch (SignErrException ex) {
            // 请求签名失败，封装失败报文
            logger.error("签名验签异常，信息为:\n" + ex);
            responseXml.exception(ex.getMessage());//生成失败报文
        } catch (SinoBizException ex) {
            // 承保业务失败，封装失败报文
            logger.error("系统业务异常，信息为：\n" + ex);
            responseXml.failture(ex.getMessage());//生成失败报文
        } catch (RpcException ex) {
            // 承保系统异常失败，封装失败报文
            logger.error("系统异常，信息为：服务调用超时");
            ex.printStackTrace();
            responseXml.exception("系统异常，信息为：服务处理超时");//生成失败报文
        } catch (Exception ex) {
            // 承保系统异常失败，封装失败报文
            logger.error("系统异常，信息为：\n" + ex);
            ex.printStackTrace();
            responseXml.exception(ex.getMessage());//生成失败报文
        } finally {
            String returnXmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + "\n" + xstream.toXML(responseXml);
            logger.info("返回报文为：" + returnXmlStr);
            //TODO  日志落地

            try {
                response.setContentType("text/html");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().print(returnXmlStr);
            } catch (Exception e) {
                //logger.error(e);
            }
        }
    }

    /**
     * 查询报文请求入口
     *
     * @param request
     * @param response
     * @Title: searchBatchMsg
     */
    @RequestMapping("/searchBatchMsg.do")
    public void searchBatchMsg(HttpServletRequest request, HttpServletResponse response) {
        SearchResponseBaseXml responseXml = newSearchResponseXml();
        SearchResponseHead resHead = new SearchResponseHead();
        //TODO 请求日志
        XStream xstreams = new XStream(new DomDriver());
        xstreams.processAnnotations(RequestSearchBaseXml.class);
        try {
            //接收请求参数
            String toDealRequest = request.getParameter("request_xml");
            String sign = request.getParameter("sign");
            //报文解密
            logger.info("请求密文为：" + toDealRequest + "签名为：" + sign);
//            String requestXml = SecurityUtil.aesDecrypt(toDealRequest, autograph);
//            logger.info("请求报文为：" + requestXml);

            //解析报文转换为请求报文标准DTO
            RequestSearchBaseXml requestObj = (RequestSearchBaseXml) xstreams.fromXML(toDealRequest);
            //封装报文头为请求参数标准DTO
            RequestParamsDTO requestParams = getRequestMustParamsForSearch(requestObj.getQueryBatchTransHead());
            //获得业务类型，并校验业务类型合法性（是否存在该业务类型）
            String bizType = requestParams.getBatchBizType();
            String bizValue = ENUM_BIZ_TRANSTYPE.getEnumValueByKey(bizType);
            if (StringUtil.isEmpty(bizValue)) {
                throw new BizDataErrException("业务类型错误，非法业务类型为" + bizType);
            }
            String sourceCode = requestParams.getMerchantCode();//商户编码
            String serialNo = requestParams.getBatchSerialNo();//业务流水号
            //报文验证签名及商户编码合法性
            //paymentBatchService.getAllMerchantSignKeys(sign, toDealRequest,sourceCode);
            //初始化返回报文头
            resHead.setSerialNo(serialNo);//业务流水号
            resHead.setMerchantCode(sourceCode);//商户编码
            responseXml.setResHead(resHead);//生成返回报文头
            
            //TODO 生成记录报文日志

            //调用服务，获得报文体
            SearchResultInfo result = batchPayService.searchBizService(requestObj);
            //封装成功报文
            responseXml.success();//生成返回报文，初始化报文头
            responseXml.setResponseBody(result);//报文体
        } catch (SignErrException ex) {
            // 请求签名失败，封装失败报文
            logger.error("签名验签异常，信息为:\n" + ex);
            responseXml.exception(ex.getMessage());//生成失败报文
        } catch (SinoBizException ex) {
            // 承保业务失败，封装失败报文
            logger.error("系统业务异常，信息为：\n" + ex);
            responseXml.failture(ex.getMessage());//生成失败报文
        } catch (RpcException ex) {
            // 承保系统异常失败，封装失败报文
            logger.error("系统异常，信息为：服务调用超时");
            ex.printStackTrace();
            responseXml.exception("系统异常，信息为：服务处理超时");//生成失败报文
        } catch (Exception ex) {
            // 承保系统异常失败，封装失败报文
            logger.error("系统异常，信息为：\n" + ex);
            ex.printStackTrace();
            responseXml.exception(ex.getMessage());//生成失败报文
        } finally {
            String returnXmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + "\n" + xstreams.toXML(responseXml);
            logger.info("返回报文为：" + returnXmlStr);
            //TODO  日志落地

            try {
                response.setContentType("text/html");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().print(returnXmlStr);
            } catch (Exception e) {
                //logger.error(e);
            }
        }
    }


    /**
     * 新建返回报文实例
     *
     * @return
     */
    protected ResponseBaseXml newResponseXml() {
        return new BatchResponseXML();
    }

    protected SearchResponseBaseXml newSearchResponseXml() {return new SearchResponseXML();}




    /**
     * 获取请求常规必要参数
     *
     * @param requestObj
     * @return
     * @Title: getRequestMustParams
     * @Description: <p>从请求报文中抽出常规参数，封装到RequestParamsDTO中 </p>
     */
    protected RequestParamsDTO getRequestMustParams(RequestHead requestObj) {
        String tSign = requestObj.getSign();
        String tPayType = requestObj.getPayType();
        String tMerchantCode = requestObj.getMerchantCode();
        String tBatchBizType = requestObj.getBatchBizType();
        String tBatchSerialNo = requestObj.getBatchSerialNo();
        checkStrEmpty("Sign", tSign);
        checkStrEmpty("PayType", tPayType);
        checkStrEmpty("MerchantCode", tMerchantCode);
        checkStrEmpty("BatchBizType", tBatchBizType);
        checkStrEmpty("BatchSerialNo", tBatchSerialNo);
        RequestParamsDTO result = new RequestParamsDTO();
        result.setSign(tSign);
        result.setMerchantCode(tMerchantCode);
        result.setBatchBizType(tBatchBizType);
        result.setPayType(tPayType);
        result.setBatchSerialNo(tBatchSerialNo);
        return result;
    }

    /**
     * 获取请求常规必要参数
     *
     * @param requestObj
     * @return
     * @Title: getRequestMustParams
     * @Description: <p>从请求报文中抽出常规参数，封装到RequestParamsDTO中 </p>
     */
    protected RequestParamsDTO getRequestMustParamsForSearch(SearchHead requestObj) {
        String tSign = requestObj.getSign();
        String tMerchantCode = requestObj.getMerchantCode();
        String tBatchBizType = requestObj.getBatchBizType();
        String tBatchSerialNo = requestObj.getBatchSerialNo();
        checkStrEmpty("Sign", tSign);
        checkStrEmpty("MerchantCode", tMerchantCode);
        checkStrEmpty("BatchBizType", tBatchBizType);
        checkStrEmpty("BatchSerialNo", tBatchSerialNo);
        RequestParamsDTO result = new RequestParamsDTO();
        result.setSign(tSign);
        result.setMerchantCode(tMerchantCode);
        result.setBatchBizType(tBatchBizType);
        result.setBatchSerialNo(tBatchSerialNo);
        return result;
    }

    private boolean checkStrEmpty(String keys, String key) {
        if (StringUtil.isBlank(key)) {
            return false;
        } else {
            return true;
        }
    }

}
